﻿using System.Collections.Generic;
using System.Linq;

namespace OpenWaves.Pagination
{
    public static class EnumerableExtensions
    {
        public static PaginationViewModel<T> Paginate<T>(this IEnumerable<T> items, int pageSize, int currentPageIndex, int maxNumberOfPagesToShow = 5)
        {
            int totalItemsCount;
            var pages = items.Paginate(pageSize, out totalItemsCount);
            return PaginationViewModel.Create(totalItemsCount, pages, currentPageIndex, maxNumberOfPagesToShow);
        }

        public static PageViewModel<T> GetPage<T>(this IEnumerable<T> items, int pageSize, int pageIndex)
        {
            var page = new Page<T>(items, pageIndex, pageSize);

            return new PageViewModel<T>(page, pageIndex == 0, page.IsLast, true);
        }

        private class Page<T> : IPage<T>
        {
            private readonly IEnumerable<T> items;
            private readonly int index;
            private readonly int pageSize;
            private readonly int firstItemIndex;

            private bool isLast;
            private int lastItemIndex;
            private IEnumerable<T> itemsRange; 

            public Page(IEnumerable<T> items, int index, int pageSize)
            {
                this.items = items;
                this.index = index;
                this.pageSize = pageSize;
                this.firstItemIndex = index * pageSize;
            }

            public int Index
            {
                get { return this.index; }
            }

            public int FirstItemIndex
            {
                get { return this.firstItemIndex; }
            }

            public int LastItemIndex
            {
                get
                {
                    this.EnsureItemsRange();
                    return this.lastItemIndex;
                }
            }

            public bool IsLast
            {
                get
                {
                    this.EnsureItemsRange();
                    return this.isLast;
                }
            }

            public IEnumerable<T> GetItemsRange()
            {
                return this.EnsureItemsRange();
            }

            private IEnumerable<T> EnsureItemsRange()
            {
                if (this.itemsRange == null)
                {
                    var range = this.items.GetRange(this.firstItemIndex, this.pageSize + 1).ToList();
                    if (range.Count <= this.pageSize)
                    {
                        this.isLast = true;
                    }
                    else
                    {
                        this.isLast = false;
                        range.RemoveAt(range.Count - 1);
                    }
                    this.lastItemIndex = this.firstItemIndex + range.Count;
                    this.itemsRange = range;
                }

                return this.itemsRange;
            }
        }
    }
}